package com.upittc.flopol.core;

import java.util.Map;

import com.upittc.flopol.constant.ErrorConstant;
import com.upittc.flopol.constant.FlopolConstant;
import com.upittc.flopol.core.beans.Symbol;
import com.upittc.flopol.core.helper.CoreHelper;

public class SemanticAnalyzer{
	
	public static Map <String, Symbol> symtbl = null;
	
	public static void initSemanticAnalyzer(Map <String, Symbol> symtbl){
		SemanticAnalyzer.symtbl = symtbl;
	}
	
	//TYPE CHECKING
	public static void checkValue(Symbol symbol, int token, int lineNo, String lexeme, int op) throws Exception{
		if(symbol.getVarName() != null){
			if(op == FlopolConstant.GLOBAL_VAR){
				checkDuplicateVariable(symbol.getVarName());
			}
			if(op == FlopolConstant.ASSIGN_VAR){
				checkExistingVariable(symbol.getVarName());
			}
		}
		if (token == FlopolConstant.IDENT){
			symbol = symtbl.get(lexeme);
			if(symbol != null){
				token = CoreHelper.tokenVal(symbol.getVarType());
			}
		}
		if(op == FlopolConstant.GLOBAL_VAR || op == FlopolConstant.ASSIGN_VAR){
			if(symbol.getVarType() == null) {
				if (token != FlopolConstant.IDENT && token != FlopolConstant.FLT_LIT && token != FlopolConstant.STR_LIT && token != FlopolConstant.BOL_LIT){
					throw new Exception(CoreHelper.setErrorSem(ErrorConstant.INVALID_ASSIGN, lineNo));
				}
			} else {
				if(symbol.getVarType().equals(FlopolConstant.FLOAT)){
					if(token != FlopolConstant.FLT_LIT){
						throw new Exception(CoreHelper.setErrorSem(ErrorConstant.INVALID_ASSIGN, lineNo));
					}
				} else if (symbol.getVarType().equals(FlopolConstant.STRING)){
					if(token != FlopolConstant.STR_LIT){
						throw new Exception(CoreHelper.setErrorSem(ErrorConstant.INVALID_ASSIGN, lineNo));
					}
				} else if (symbol.getVarType().equals(FlopolConstant.BOOL)){
					if(token != FlopolConstant.BOL_LIT){
						throw new Exception(CoreHelper.setErrorSem(ErrorConstant.INVALID_ASSIGN, lineNo));
					}
				} 
			}
		} else if (op == FlopolConstant.REL_OP || op == FlopolConstant.NUM_OP || op == FlopolConstant.UNARY_OP){
			if(token != FlopolConstant.FLT_LIT){
				throw new Exception(CoreHelper.setErrorSem(ErrorConstant.INVALID_ASSIGN, lineNo));
			}
		} else if (op == FlopolConstant.LOG_OP  || op == FlopolConstant.NOT_OP){
			if(token != FlopolConstant.BOL_LIT){
				throw new Exception(CoreHelper.setErrorSem(ErrorConstant.INVALID_ASSIGN, lineNo));
			}
		}
		
	}
	
	//CHECK DUPLICATE VARIABLE
	private static void checkDuplicateVariable(String lexeme) throws Exception{
		Symbol tokenDummy = symtbl.get(lexeme);
		if (tokenDummy != null) {
			throw new Exception(CoreHelper.setErrorSem(ErrorConstant.DUP_IDENTIFIER, lexeme));
		} 
	}
	
	//CHECK EXISTING VARIABLE
	private static void checkExistingVariable(String lexeme) throws Exception{
		Symbol tokenDummy = symtbl.get(lexeme);
		if (tokenDummy == null) {
			throw new Exception(CoreHelper.setErrorSem(ErrorConstant.NOT_EXISTING_ID, lexeme));
		} 
	}

	//CHECK IF INPUT IS CORRECT TYPE
	public static void checkValueInput(String varVal, int nextToken, int lineNo) throws Exception {
		Lexer lexer = new Lexer(varVal+FlopolConstant.EOF);
		lexer.lexer();
		if(lexer.getNextToken().getToken() != nextToken){
			throw new Exception(CoreHelper.setErrorSem(ErrorConstant.INVALID_ASSIGN, lineNo));
		}
	}
	
	//CHECK IF INPUT IS STRING
	public static int checkValueInput(String varVal) throws Exception {
		Lexer lexer = new Lexer(varVal+FlopolConstant.EOF);
		lexer.lexer();
		return lexer.getNextToken().getToken();
	}
	
	//CHEKCK IS BOOL 
	public static void checkBool(String val) throws Exception{
		if(!val.equals(FlopolConstant.YEAH) && !val.equals(FlopolConstant.NOPE)){
			throw new Exception(CoreHelper.setErrorSem(ErrorConstant.INVALID_ASSIGN, val));
		}
	}
	
	//CHEKCK IS FLOAT 
	public static float checkAndGetFloat(String varVal) throws Exception{
		Lexer lexer = new Lexer(varVal+FlopolConstant.EOF);
		lexer.lexer();
		int isFloat = lexer.getNextToken().getToken();
		String floatVal = lexer.getNextToken().getLexeme();
		Float floatNo = Float.parseFloat(floatVal);
		if(isFloat != FlopolConstant.FLT_LIT){
			throw new Exception(CoreHelper.setErrorSem(ErrorConstant.INVALID_ASSIGN, floatVal));
		} 
		if (floatNo < 0){
			throw new Exception(CoreHelper.setErrorSem(ErrorConstant.INVALID_PERFORM, floatVal));
		}
		return floatNo;
	}
	
	public static void checkEOF(int nextToken) throws Exception{
		if(nextToken == FlopolConstant.EOFF){
			throw new Exception(CoreHelper.setErrorWoLine(ErrorConstant.MISSING_RBR));
		}
	}
	
	
}
